package com.sky.skyopsserver.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.skyopsserver.domain.Host;
import com.sky.skyopsserver.enums.HostTypeEnum;
import com.sky.skyopsserver.enums.ResponseCodeEnum;
import com.sky.skyopsserver.exception.BizException;
import com.sky.skyopsserver.mapper.HostMapper;
import com.sky.skyopsserver.service.HostService;
import com.sky.skyopsserver.vos.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 主机信息服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class HostServiceImpl extends ServiceImpl<HostMapper, Host> implements HostService {

    private static final Pattern IP_PATTERN = Pattern.compile(
            "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addHost(HostAddReqVO reqVO) {
        log.info("开始添加主机，名称: {}", reqVO.getName());
        
        // 验证主机类型
        if (!validateHostType(reqVO.getType())) {
            throw new BizException(ResponseCodeEnum.HOST_TYPE_INVALID);
        }
        
        // 检查主机名称是否已存在
        if (checkHostNameExists(reqVO.getName(), null)) {
            throw new BizException(ResponseCodeEnum.HOST_NAME_EXISTS);
        }
        
        // 检查IP地址是否已存在
        if (StringUtils.hasText(reqVO.getPublicHost()) && checkHostIpExists(reqVO.getPublicHost(), null)) {
            throw new BizException(ResponseCodeEnum.HOST_IP_EXISTS);
        }
        
        if (StringUtils.hasText(reqVO.getPrivateHost()) && checkHostIpExists(reqVO.getPrivateHost(), null)) {
            throw new BizException(ResponseCodeEnum.HOST_IP_EXISTS);
        }
        
        // 验证IP地址格式
        if (StringUtils.hasText(reqVO.getPublicHost()) && !validateIpAddress(reqVO.getPublicHost())) {
            throw new BizException(ResponseCodeEnum.HOST_IP_INVALID);
        }
        
        if (StringUtils.hasText(reqVO.getPrivateHost()) && !validateIpAddress(reqVO.getPrivateHost())) {
            throw new BizException(ResponseCodeEnum.HOST_IP_INVALID);
        }
        
        // 验证端口
        if (Objects.nonNull(reqVO.getPort()) && !validatePort(reqVO.getPort())) {
            throw new BizException(ResponseCodeEnum.HOST_PORT_INVALID);
        }
        
        // 构建主机实体
        Host host = new Host();
        BeanUtils.copyProperties(reqVO, host);
        host.setCreateTime(LocalDateTime.now());
        host.setUpdateTime(LocalDateTime.now());
        
        // 保存到数据库
        boolean saved = save(host);
        if (!saved) {
            throw new BizException(ResponseCodeEnum.HOST_ADD_FAILED);
        }
        
        log.info("主机添加成功，主机ID: {}", host.getId());
        return host.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateHost(HostUpdateReqVO reqVO) {
        log.info("开始更新主机，主机ID: {}", reqVO.getId());
        
        // 检查主机是否存在
        Host existingHost = getById(reqVO.getId());
        if (Objects.isNull(existingHost)) {
            throw new BizException(ResponseCodeEnum.HOST_NOT_EXISTS);
        }
        
        // 验证主机类型
        if (!validateHostType(reqVO.getType())) {
            throw new BizException(ResponseCodeEnum.HOST_TYPE_INVALID);
        }
        
        // 检查主机名称是否已存在（排除当前主机）
        if (checkHostNameExists(reqVO.getName(), reqVO.getId())) {
            throw new BizException(ResponseCodeEnum.HOST_NAME_EXISTS);
        }
        
        // 检查IP地址是否已存在（排除当前主机）
        if (StringUtils.hasText(reqVO.getPublicHost()) && checkHostIpExists(reqVO.getPublicHost(), reqVO.getId())) {
            throw new BizException(ResponseCodeEnum.HOST_IP_EXISTS);
        }
        
        if (StringUtils.hasText(reqVO.getPrivateHost()) && checkHostIpExists(reqVO.getPrivateHost(), reqVO.getId())) {
            throw new BizException(ResponseCodeEnum.HOST_IP_EXISTS);
        }
        
        // 验证IP地址格式
        if (StringUtils.hasText(reqVO.getPublicHost()) && !validateIpAddress(reqVO.getPublicHost())) {
            throw new BizException(ResponseCodeEnum.HOST_IP_INVALID);
        }
        
        if (StringUtils.hasText(reqVO.getPrivateHost()) && !validateIpAddress(reqVO.getPrivateHost())) {
            throw new BizException(ResponseCodeEnum.HOST_IP_INVALID);
        }
        
        // 验证端口
        if (Objects.nonNull(reqVO.getPort()) && !validatePort(reqVO.getPort())) {
            throw new BizException(ResponseCodeEnum.HOST_PORT_INVALID);
        }
        
        // 更新主机信息
        Host host = new Host();
        BeanUtils.copyProperties(reqVO, host);
        host.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(host);
        if (!updated) {
            throw new BizException(ResponseCodeEnum.HOST_UPDATE_FAILED);
        }
        
        log.info("主机更新成功，主机ID: {}", reqVO.getId());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteHost(Long id) {
        log.info("开始删除主机，主机ID: {}", id);
        
        // 检查主机是否存在
        Host existingHost = getById(id);
        if (Objects.isNull(existingHost)) {
            throw new BizException(ResponseCodeEnum.HOST_NOT_EXISTS);
        }
        
        boolean deleted = removeById(id);
        if (!deleted) {
            throw new BizException(ResponseCodeEnum.HOST_DELETE_FAILED);
        }
        
        log.info("主机删除成功，主机ID: {}", id);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchDeleteHost(List<Long> ids) {
        log.info("开始批量删除主机，主机ID列表: {}", ids);
        
        if (CollectionUtils.isEmpty(ids)) {
            throw new BizException(ResponseCodeEnum.PARAM_NOT_VALID);
        }
        
        // 检查所有主机是否存在
        List<Host> existingHosts = listByIds(ids);
        if (existingHosts.size() != ids.size()) {
            throw new BizException(ResponseCodeEnum.HOST_NOT_EXISTS);
        }
        
        boolean deleted = removeByIds(ids);
        if (!deleted) {
            throw new BizException(ResponseCodeEnum.HOST_DELETE_FAILED);
        }
        
        log.info("主机批量删除成功，删除数量: {}", ids.size());
        return true;
    }

    @Override
    public HostRspVO getHostById(Long id) {
        log.info("查询主机详情，主机ID: {}", id);
        
        Host host = getById(id);
        if (Objects.isNull(host)) {
            throw new BizException(ResponseCodeEnum.HOST_NOT_EXISTS);
        }
        
        return convertToRspVO(host);
    }

    @Override
    public HostRspVO getHostByName(String name) {
        log.info("根据名称查询主机，主机名称: {}", name);
        
        Host host = getOne(new LambdaQueryWrapper<Host>()
                .eq(Host::getName, name));
        
        if (Objects.isNull(host)) {
            throw new BizException(ResponseCodeEnum.HOST_NOT_EXISTS);
        }
        
        return convertToRspVO(host);
    }

    @Override
    public IPage<HostRspVO> getHostPage(HostPageReqVO reqVO) {
        log.info("分页查询主机列表，查询条件: {}", reqVO);
        
        // 构建分页对象
        Page<Host> page = new Page<>(reqVO.getCurrent(), reqVO.getSize());
        
        // 构建查询条件
        LambdaQueryWrapper<Host> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(reqVO.getName()), Host::getName, reqVO.getName())
                   .like(StringUtils.hasText(reqVO.getRoomName()), Host::getRoomName, reqVO.getRoomName())
                   .eq(Objects.nonNull(reqVO.getRoomId()), Host::getRoomId, reqVO.getRoomId())
                   .like(StringUtils.hasText(reqVO.getGroupName()), Host::getGroupName, reqVO.getGroupName())
                   .eq(Objects.nonNull(reqVO.getGroupId()), Host::getGroupId, reqVO.getGroupId())
                   .like(StringUtils.hasText(reqVO.getPublicHost()), Host::getPublicHost, reqVO.getPublicHost())
                   .like(StringUtils.hasText(reqVO.getPrivateHost()), Host::getPrivateHost, reqVO.getPrivateHost())
                   .eq(StringUtils.hasText(reqVO.getType()), Host::getType, reqVO.getType())
                   .like(StringUtils.hasText(reqVO.getOsVersion()), Host::getOsVersion, reqVO.getOsVersion())
                   .like(StringUtils.hasText(reqVO.getRemark()), Host::getRemark, reqVO.getRemark())
                   .orderByDesc(Host::getCreateTime);
        
        // 执行分页查询
        IPage<Host> hostPage = page(page, queryWrapper);
        
        // 转换为响应VO
        IPage<HostRspVO> rspPage = hostPage.convert(this::convertToRspVO);
        
        log.info("分页查询主机列表完成，总记录数: {}", rspPage.getTotal());
        return rspPage;
    }

    @Override
    public List<HostOptionRspVO> getAllHostOptions() {
        log.info("查询所有主机选项");
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .orderByAsc(Host::getName));
        
        return hosts.stream()
                .map(this::convertToOptionRspVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<HostOptionRspVO> getHostOptionsByRoomId(Long roomId) {
        log.info("根据机房ID查询主机选项，机房ID: {}", roomId);
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .eq(Host::getRoomId, roomId)
                .orderByAsc(Host::getName));
        
        return hosts.stream()
                .map(this::convertToOptionRspVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<HostOptionRspVO> getHostOptionsByGroupId(Long groupId) {
        log.info("根据主机组ID查询主机选项，主机组ID: {}", groupId);
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .eq(Host::getGroupId, groupId)
                .orderByAsc(Host::getName));
        
        return hosts.stream()
                .map(this::convertToOptionRspVO)
                .collect(Collectors.toList());
    }

    @Override
    public HostStatisticsRspVO getHostStatistics() {
        log.info("获取主机统计信息");
        
        // 主机总数
        long totalCount = count();
        
        // 各类型数量统计
        long physicalCount = count(new LambdaQueryWrapper<Host>()
                .eq(Host::getType, "physical"));
        
        long virtualCount = count(new LambdaQueryWrapper<Host>()
                .eq(Host::getType, "virtual"));
        
        long containerCount = count(new LambdaQueryWrapper<Host>()
                .eq(Host::getType, "container"));
        
        long cloudCount = count(new LambdaQueryWrapper<Host>()
                .eq(Host::getType, "cloud"));
        
        // 在线/离线统计（这里简化处理，实际可能需要连接测试）
        long onlineCount = count(new LambdaQueryWrapper<Host>()
                .isNotNull(Host::getPublicHost)
                .or()
                .isNotNull(Host::getPrivateHost));
        
        long offlineCount = totalCount - onlineCount;
        
        // 过期主机统计
        LocalDateTime now = LocalDateTime.now();
        long expiredCount = count(new LambdaQueryWrapper<Host>()
                .lt(Host::getExpirationTime, now));
        
        // 时间统计
        LocalDateTime today = LocalDateTime.now().with(LocalTime.MIN);
        LocalDateTime weekStart = today.minusDays(today.getDayOfWeek().getValue() - 1);
        LocalDateTime monthStart = today.withDayOfMonth(1);
        
        long todayAddedCount = count(new LambdaQueryWrapper<Host>()
                .ge(Host::getCreateTime, today));
        
        long weeklyAddedCount = count(new LambdaQueryWrapper<Host>()
                .ge(Host::getCreateTime, weekStart));
        
        long monthlyAddedCount = count(new LambdaQueryWrapper<Host>()
                .ge(Host::getCreateTime, monthStart));
        
        // 硬件统计
        List<Host> allHosts = list();
        double totalMemory = allHosts.stream()
                .filter(host -> Objects.nonNull(host.getMemory()))
                .mapToDouble(Host::getMemory)
                .sum();
        
        int totalCpuCount = allHosts.stream()
                .filter(host -> Objects.nonNull(host.getCpuCount()))
                .mapToInt(Host::getCpuCount)
                .sum();
        
        // 机房和主机组统计
        long totalRoomCount = list().stream()
                .map(Host::getRoomId)
                .filter(Objects::nonNull)
                .distinct()
                .count();
        
        long totalGroupCount = list().stream()
                .map(Host::getGroupId)
                .filter(Objects::nonNull)
                .distinct()
                .count();
        
        return HostStatisticsRspVO.builder()
                .totalCount(totalCount)
                .physicalCount(physicalCount)
                .virtualCount(virtualCount)
                .containerCount(containerCount)
                .cloudCount(cloudCount)
                .onlineCount(onlineCount)
                .offlineCount(offlineCount)
                .expiredCount(expiredCount)
                .todayAddedCount(todayAddedCount)
                .weeklyAddedCount(weeklyAddedCount)
                .monthlyAddedCount(monthlyAddedCount)
                .totalMemory(totalMemory)
                .totalCpuCount(totalCpuCount)
                .totalRoomCount(totalRoomCount)
                .totalGroupCount(totalGroupCount)
                .build();
    }

    @Override
    public Boolean checkHostNameExists(String name, Long excludeId) {
        LambdaQueryWrapper<Host> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Host::getName, name);
        if (Objects.nonNull(excludeId)) {
            queryWrapper.ne(Host::getId, excludeId);
        }
        return count(queryWrapper) > 0;
    }

    @Override
    public Boolean checkHostIpExists(String ip, Long excludeId) {
        LambdaQueryWrapper<Host> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper
                .eq(Host::getPublicHost, ip)
                .or()
                .eq(Host::getPrivateHost, ip)
                .or()
                .eq(Host::getSshHost, ip));
        
        if (Objects.nonNull(excludeId)) {
            queryWrapper.ne(Host::getId, excludeId);
        }
        return count(queryWrapper) > 0;
    }

    @Override
    public List<HostRspVO> searchHostByName(String name) {
        log.info("根据名称模糊查询主机，名称关键字: {}", name);
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .like(Host::getName, name)
                .orderByAsc(Host::getName));
        
        return hosts.stream()
                .map(this::convertToRspVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<HostRspVO> getHostsByRoomId(Long roomId) {
        log.info("获取机房下的主机列表，机房ID: {}", roomId);
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .eq(Host::getRoomId, roomId)
                .orderByAsc(Host::getName));
        
        return hosts.stream()
                .map(this::convertToRspVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<HostRspVO> getHostsByGroupId(Long groupId) {
        log.info("获取主机组下的主机列表，主机组ID: {}", groupId);
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .eq(Host::getGroupId, groupId)
                .orderByAsc(Host::getName));
        
        return hosts.stream()
                .map(this::convertToRspVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<HostRspVO> getHostsByType(String type) {
        log.info("根据主机类型查询主机，主机类型: {}", type);
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .eq(Host::getType, type)
                .orderByAsc(Host::getName));
        
        return hosts.stream()
                .map(this::convertToRspVO)
                .collect(Collectors.toList());
    }

    @Override
    public Boolean validateHostType(String type) {
        return HostTypeEnum.isValid(type);
    }

    @Override
    public Boolean validateIpAddress(String ip) {
        return StringUtils.hasText(ip) && IP_PATTERN.matcher(ip).matches();
    }

    @Override
    public Boolean validatePort(Integer port) {
        return Objects.nonNull(port) && port > 0 && port <= 65535;
    }

    @Override
    public Boolean testHostConnection(Long id) {
        log.info("测试主机连接，主机ID: {}", id);
        
        Host host = getById(id);
        if (Objects.isNull(host)) {
            throw new BizException(ResponseCodeEnum.HOST_NOT_EXISTS);
        }
        
        // 这里可以实现具体的连接测试逻辑
        // 例如SSH连接测试、ping测试等
        log.info("主机连接测试完成，主机: {}", host.getName());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean moveHostsToGroup(List<Long> hostIds, Long targetGroupId) {
        log.info("移动主机到主机组，主机ID列表: {}, 目标主机组ID: {}", hostIds, targetGroupId);
        
        if (CollectionUtils.isEmpty(hostIds)) {
            throw new BizException(ResponseCodeEnum.PARAM_NOT_VALID);
        }
        
        // 检查所有主机是否存在
        List<Host> hosts = listByIds(hostIds);
        if (hosts.size() != hostIds.size()) {
            throw new BizException(ResponseCodeEnum.HOST_NOT_EXISTS);
        }
        
        // 批量更新主机组信息
        hosts.forEach(host -> {
            host.setGroupId(targetGroupId);
            host.setUpdateTime(LocalDateTime.now());
        });
        
        boolean updated = updateBatchById(hosts);
        if (!updated) {
            throw new BizException(ResponseCodeEnum.HOST_UPDATE_FAILED);
        }
        
        log.info(" moveHostsToGroup 主机移动成功，移动数量: {}", hosts.size());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean moveHostsToRoom(List<Long> hostIds, Long targetRoomId) {
        log.info("移动主机到机房，主机ID列表: {}, 目标机房ID: {}", hostIds, targetRoomId);
        
        if (CollectionUtils.isEmpty(hostIds)) {
            throw new BizException(ResponseCodeEnum.PARAM_NOT_VALID);
        }
        
        // 检查所有主机是否存在
        List<Host> hosts = listByIds(hostIds);
        if (hosts.size() != hostIds.size()) {
            throw new BizException(ResponseCodeEnum.HOST_NOT_EXISTS);
        }
        
        // 批量更新机房信息
        hosts.forEach(host -> {
            host.setRoomId(targetRoomId);
            host.setUpdateTime(LocalDateTime.now());
        });
        
        boolean updated = updateBatchById(hosts);
        if (!updated) {
            throw new BizException(ResponseCodeEnum.HOST_UPDATE_FAILED);
        }
        
        log.info("主机移动成功，移动数量: {}", hosts.size());
        return true;
    }

    @Override
    public List<String> getAllHostNames() {
        log.info("获取所有主机名称列表");
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .select(Host::getName)
                .orderByAsc(Host::getName));
        
        return hosts.stream()
                .map(Host::getName)
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getAllHostIps() {
        log.info("获取所有主机IP列表");
        
        List<Host> hosts = list();
        return hosts.stream()
                .flatMap(host -> Stream.of(
                        host.getPublicHost(),
                        host.getPrivateHost(),
                        host.getSshHost()
                ))
                .filter(StringUtils::hasText)
                .distinct()
                .sorted()
                .collect(Collectors.toList());
    }

    @Override
    public Long getHostCountByRoomId(Long roomId) {
        return count(new LambdaQueryWrapper<Host>()
                .eq(Host::getRoomId, roomId));
    }

    @Override
    public Long getHostCountByGroupId(Long groupId) {
        return count(new LambdaQueryWrapper<Host>()
                .eq(Host::getGroupId, groupId));
    }

    @Override
    public List<HostRspVO> getExpiredHosts() {
        log.info("获取过期主机列表");
        
        LocalDateTime now = LocalDateTime.now();
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .lt(Host::getExpirationTime, now)
                .orderByAsc(Host::getExpirationTime));
        
        return hosts.stream()
                .map(this::convertToRspVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<HostRspVO> getHostsExpiringSoon(Integer days) {
        log.info("获取即将过期主机列表，天数: {}", days);
        
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime futureTime = now.plusDays(days);
        
        List<Host> hosts = list(new LambdaQueryWrapper<Host>()
                .between(Host::getExpirationTime, now, futureTime)
                .orderByAsc(Host::getExpirationTime));
        
        return hosts.stream()
                .map(this::convertToRspVO)
                .collect(Collectors.toList());
    }

    /**
     * 转换为响应VO
     */
    private HostRspVO convertToRspVO(Host host) {
        HostRspVO rspVO = new HostRspVO();
        BeanUtils.copyProperties(host, rspVO);
        
        // 设置类型描述
        HostTypeEnum typeEnum = HostTypeEnum.getByType(host.getType());
        if (typeEnum != null) {
            rspVO.setTypeDescription(typeEnum.getDescription());
        }
        
        return rspVO;
    }

    /**
     * 转换为选项响应VO
     */
    private HostOptionRspVO convertToOptionRspVO(Host host) {
        HostOptionRspVO optionVO = new HostOptionRspVO();
        BeanUtils.copyProperties(host, optionVO);
        
        // 设置类型描述
        HostTypeEnum typeEnum = HostTypeEnum.getByType(host.getType());
        if (typeEnum != null) {
            optionVO.setTypeDescription(typeEnum.getDescription());
        }
        
        return optionVO;
    }
}




